#ifndef __SG_PCL_VISUAL_H__
#define __SG_PCL_VISUAL_H__

#include "SGPCLConversion.h"
#include "SGPCLJsonConfig.h"
#include <pcl/visualization/pcl_visualizer.h>

namespace sgpcl
{
/// <summary>
/// 返回预设颜色
/// </summary>
/// <param name="nID"></param>
/// <returns></returns>
SGPCL_API std::tuple<int, int, int> GetColor(const size_t& nID);

/// <summary>
/// 视窗对象进入loop，hold等待结束
/// </summary>
/// <param name="spViewer">视窗对象</param>
SGPCL_API void ViewWait(pcl::visualization::PCLVisualizer::Ptr spViewer);

/// <summary>
/// 设置可视化通用属性
/// </summary>
/// <param name="spViewer"></param>
/// <param name="sConfig"></param>
SGPCL_API void SetupViewer(
  pcl::visualization::PCLVisualizer::Ptr spViewer, const SGVisualConfig& sConfig);

/// <summary>
/// 绘制点云
/// </summary>
/// <typeparam name="PointT">点云类型</typeparam>
/// <param name="spCloud">点云智能指针</param>
/// <param name="strCloudName">点云名称</param>
/// <param name="spViewer">输入视窗对象</param>
/// <param name="nID">点云序号（用于配色和名称）</param>
/// <returns>返回视窗对象</returns>
template <typename PointT>
pcl::visualization::PCLVisualizer::Ptr PlotCloud(
  std::shared_ptr<const pcl::PointCloud<PointT>> spCloud,
  const SGVisualConfig& sConfig = SGVisualConfig(),
  pcl::visualization::PCLVisualizer::Ptr spViewer = nullptr, const int& nID = -1,
  const bool& bSetup = true)
{
  SG_NOTIMPLEMENTED();
}

/// <summary>
/// 绘制点云的pcl::PointXYZRGBNormal特化版
/// </summary>
/// <param name="spCloud">点云智能指针</param>
/// <param name="strCloudName">点云名称</param>
/// <param name="spViewer">输入视窗对象</param>
/// <param name="nID">点云序号（用于配色和名称）</param>
/// <returns>返回视窗对象</returns>
template <>
SGPCL_API pcl::visualization::PCLVisualizer::Ptr PlotCloud<pcl::PointXYZRGBNormal>(
  std::shared_ptr<const pcl::PointCloud<pcl::PointXYZRGBNormal>> spCloud,
  const sgpcl::SGVisualConfig& sConfig, pcl::visualization::PCLVisualizer::Ptr spViewer,
  const int& nID, const bool& bSetup);

/// <summary>
/// 绘制多个点云
/// </summary>
/// <typeparam name="PointT">点云类型</typeparam>
/// <param name="vecCloud">点云智能指针</param>
/// <param name="strCloudName">点云名称</param>
/// <param name="spViewer">输入视窗对象</param>
/// <returns>返回视窗对象</returns>
template <typename PointT>
pcl::visualization::PCLVisualizer::Ptr PlotMultiCloud(
  std::vector<std::shared_ptr<const pcl::PointCloud<PointT>>>& vecCloud,
  const SGVisualConfig& sConfig = SGVisualConfig(),
  pcl::visualization::PCLVisualizer::Ptr spViewer = nullptr)
{
  // 建立视窗对象
  if (spViewer == nullptr)
    spViewer = std::make_shared<pcl::visualization::PCLVisualizer>("Multiply Cloud Plot");

  size_t nCnt = 0;
  for (pcl::PointCloud<PointT>::ConstPtr spCloud : vecCloud)
  {
    PlotCloud<PointT>(spCloud, sConfig, spViewer, nCnt++, false);
  }

  SetupViewer(spViewer, sConfig);

  return spViewer;
}

/// <summary>
/// 绘制带RGB的点云
/// </summary>
/// <param name="spCloud">点云智能指针</param>
/// <param name="strCloudName">点云名称</param>
/// <param name="spViewer">输入视窗对象</param>
/// <param name="nID">点云序号（用于配色和名称）</param>
/// <returns>返回视窗对象</returns>
template <typename PointXYZ, typename PointRGB>
pcl::visualization::PCLVisualizer::Ptr PlotCloudWithRGB(
  typename pcl::PointCloud<PointXYZ>::ConstPtr spXYZCloud,
  typename pcl::PointCloud<PointRGB>::ConstPtr spRGBCloud,
  const SGVisualConfig& sConfig = SGVisualConfig(),
  pcl::visualization::PCLVisualizer::Ptr spViewer = nullptr)
{
  // 建立视窗对象
  if (spViewer == nullptr)
    spViewer = std::make_shared<pcl::visualization::PCLVisualizer>("RGB Cloud Plot");

  // 设置点云颜色
  pcl::visualization::PointCloudColorHandlerRGBField<PointRGB> rgb(spRGBCloud);

  // 添加点云数据
  const std::string strCloudName = sConfig.strTitle;
  spViewer->addPointCloud<PointXYZ>(spXYZCloud, rgb, strCloudName);

  // 设置点云的显示（渲染）大小
  const float fPointSize = sConfig.fPointSize;
  spViewer->setPointCloudRenderingProperties(
    pcl::visualization::PCL_VISUALIZER_POINT_SIZE, fPointSize, strCloudName);

  SetupViewer(spViewer, sConfig);

  return spViewer;
}

/// <summary>
/// 绘制点云的PointXYZ特化版
/// </summary>
/// <param name="spCloud">点云智能指针</param>
/// <param name="strCloudName">点云名称</param>
/// <param name="spViewer">输入视窗对象</param>
/// <param name="nID">点云序号（用于配色和名称）</param>
/// <returns>返回视窗对象</returns>
template <>
SGPCL_API pcl::visualization::PCLVisualizer::Ptr PlotCloud<pcl::PointXYZ>(
  std::shared_ptr<const pcl::PointCloud<pcl::PointXYZ>> spCloud, const SGVisualConfig& sConfig,
  pcl::visualization::PCLVisualizer::Ptr spViewer, const int& nID, const bool& bSetup);

/// <summary>
/// 绘制点云的Normal特化版
/// </summary>
/// <param name="spCloud">点云智能指针</param>
/// <param name="strCloudName">点云名称</param>
/// <param name="spViewer">输入视窗对象</param>
/// <param name="nID">点云序号（用于配色和名称）</param>
/// <returns>返回视窗对象</returns>
template <>
SGPCL_API pcl::visualization::PCLVisualizer::Ptr PlotCloud<pcl::Normal>(
  std::shared_ptr<const pcl::PointCloud<pcl::Normal>> spCloud, const SGVisualConfig& sConfig,
  pcl::visualization::PCLVisualizer::Ptr spViewer, const int& nID, const bool& bSetup);

/// <summary>
/// 画出三维单位向量点云的半球密度等值线图
/// </summary>
/// <param name="spNorm">法向量点云</param>
/// <param name="strCloudName">点云名称</param>
/// <param name="spViewer">输入视窗对象</param>
/// <returns>返回视窗对象</returns>
SGPCL_API pcl::visualization::PCLVisualizer::Ptr plotNormalDensity(
  pcl::PointCloud<pcl::Normal>::ConstPtr spNorm, const std::string& strCloudName = "cloud",
  pcl::visualization::PCLVisualizer::Ptr spViewer = nullptr);

/// <summary>
/// 绘制带曲率属性的点云的曲率分布
/// </summary>
/// <typeparam name="PointT">点云类型</typeparam>
/// <param name="spCloud">点云智能指针</param>
/// <param name="strCloudName">点云名称</param>
/// <param name="spViewer">可视化对象</param>
/// <returns>返回可视化对象智能指针</returns>
template <typename PointT>
pcl::visualization::PCLVisualizer::Ptr PlotCloudCurvature(
  std::shared_ptr<const pcl::PointCloud<PointT>> spCloud,
  const SGVisualConfig& sConfig = SGVisualConfig(),
  pcl::visualization::PCLVisualizer::Ptr spViewer = nullptr)
{
  // 建立视窗对象
  if (spViewer == nullptr)
    spViewer = std::make_shared<pcl::visualization::PCLVisualizer>("XYZ + Curvature Plot");

  // 设置点云颜色
  pcl::visualization::PointCloudColorHandlerGenericField<PointT> rgb(spCloud, "curvature");

  // 添加点云数据
  const std::string strCloudName = sConfig.strTitle;
  spViewer->addPointCloud<PointT>(spCloud, rgb, strCloudName);

  // 设置点云的显示（渲染）大小
  const float fPointSize = sConfig.fPointSize;
  spViewer->setPointCloudRenderingProperties(
    pcl::visualization::PCL_VISUALIZER_POINT_SIZE, fPointSize, strCloudName);

  SetupViewer(spViewer, sConfig);

  return spViewer;
}

/// <summary>
/// 绘制带曲率属性的点云的曲率分布
/// </summary>
/// <typeparam name="PointT">点云类型</typeparam>
/// <param name="spCloud">点云智能指针</param>
/// <param name="strCloudName">点云名称</param>
/// <param name="spViewer">可视化对象</param>
/// <returns>返回可视化对象智能指针</returns>
template <typename PointT>
pcl::visualization::PCLVisualizer::Ptr PlotCloudNorm(
  std::shared_ptr<const pcl::PointCloud<PointT>> spCloud,
  const SGVisualConfig& sConfig = SGVisualConfig(),
  pcl::visualization::PCLVisualizer::Ptr spViewer = nullptr)
{
  // 建立视窗对象
  if (spViewer == nullptr)
    spViewer = std::make_shared<pcl::visualization::PCLVisualizer>("XYZ + Normal Plot");

  // 设置点云颜色
  pcl::visualization::PointCloudColorHandlerRandom<PointT> rgb(spCloud);

  // 添加点云数据
  const std::string strCloudName = sConfig.strTitle;
  spViewer->addPointCloud<PointT>(spCloud, rgb, strCloudName);

  // 设置点云的显示（渲染）大小
  spViewer->setPointCloudRenderingProperties(
    pcl::visualization::PCL_VISUALIZER_POINT_SIZE, sConfig.fPointSize, strCloudName);

  // 添加法向量数据
  spViewer->addPointCloudNormals<PointT>(
    spCloud, sConfig.nVecLevel, sConfig.fVecSize, strCloudName + "_norms");

  SetupViewer(spViewer, sConfig);

  return spViewer;
}

/// <summary>
/// 绘制平面
/// </summary>
/// <param name="coefficient">平面参数 aX+bY+cZ+d = 0 </param>
/// <param name="x">该点投影作为平面中心</param>
/// <param name="y">该点投影作为平面中心</param>
/// <param name="z">该点投影作为平面中心</param>
/// <param name="alpha">透明度</param>
/// <param name="strPlaneName">名称</param>
/// <param name="spViewer">视窗对象</param>
/// <returns>视窗对象</returns>
SGPCL_API pcl::visualization::PCLVisualizer::Ptr PlotPlane(const Eigen::VectorXf& coefficient,
  const float& x, const float& y, const float& z, const float& alpha = 0.5,
  const std::string& strPlaneName = "plane",
  pcl::visualization::PCLVisualizer::Ptr spViewer = nullptr);

/// <summary>
///
/// </summary>
/// <param name="coefficients"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="z"></param>
/// <param name="scale"></param>
/// <returns></returns>
SGPCL_API vtkSmartPointer<vtkPolyData> createPlane(
  const pcl::ModelCoefficients& coefficients, float x, float y, float z, float scale = 1.f);
}

#endif // !__SG_PCL_VISUAL_H__
